/*
 * Menu: Decode text and transmit ir code for Zte
 * Author: Johnson
 * Date: 2014-6-23
 * */
#include <stdio.h>
#include <stdlib.h>
#include <jni.h>
#include <string.h>
#include <math.h>
#include <android/log.h>

#define DEBUG_TAG   "NDK_MainActivity"
#define  LOG_TAG    "com.yaokan.devices.wavir"
#define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define  LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)

const double PI = 3.141592653589793f;

char u_key[] = { "ABCDEFGHIJKLMNOPQRSTUVWXYZ" }; // 源串为数字的处理
char n_key[] = { "0123456789" }; // 源串为逗号的处理
char pub_key[] = { "4986532710" }; // 公钥- 中兴:4986532710,  小米:9876543210

// 计算字符个数
int count_c(const char *str, char ch) {
	int count = 0;
	while (*str)
		if (*str++ == ch)
			count++;
	return count;
}

/*
 * 参数: k - 密钥（jstring k）,  e - 密文
 * 返回: 1 成功发送,  -1 失败 [LogCat中显示出错信息]
 * */
//int Java_com_yaokan_devices_wavir_transmitIR(JNIEnv * env, jobject this, jobject context, jstring e) {
int Java_com_yaokan_devices_wavir_transmitIR(JNIEnv * env, jobject this,
		jstring e) {
//	 LOGI("program start");
	jboolean isCopy;
	int i, j, pub_len, u_len, pos, cmd_size;
	char ch_t, ch_e, ch_s;
	jint cf = 0; // 频率， 码值

//	jclass android_content_Context =(*env)->GetObjectClass(env, context);
	//jclass android_content_Context = (*env)->FindClass(env, "android/content/Context");
	const char * encode = (*env)->GetStringUTFChars(env, e, &isCopy);
	//const char * pub_key = (*env)->GetStringUTFChars(env, k, &isCopy);
	char *source = (char *) malloc(strlen(encode) + 1);
	memset(source, 0, strlen(encode) + 1);

	// LOGI("sizeof(encoder):%d 密文:[%s]", strlen(encode), encode);
	char ch_c = ',';
	char *ch_find = NULL;
	int isEven = 1; // 命令码的长度 0:奇数, 1:偶数

	pub_len = strlen(pub_key);
	u_len = strlen(u_key);
	i = 0;
	j = strlen(encode);

	// 判断是明文，还是密文
	cmd_size = count_c(encode, ch_c);

//	LOGI(" status: %d ", cmd_size);

	if (cmd_size > 0) {
		// 明文
//		LOGI(" text, do not need to decode ");
		for (i = 0; i < j; i++) {
			source[i] = encode[i];
		}
		source[i] = '\0';
	} else {

		// 解码 start
		for (i = 0; i < j; i++) {
			ch_e = encode[i];
			//LOGI("位置:[%d] 密文 [%c], pub_len: %d", i, ch_e, pub_len);
			if (ch_e > 47 && ch_e < 58) { // 逗号的处理
//			LOGI(" 逗号 [%c] ", ch_e);
				source[i] = ',';
			} else {
				// 数字的处理
				pos = i % pub_len;
				ch_t = pub_key[pos]; // 进行运算的字符: 从token中取一个
				//LOGI("     公钥 位置:%d 字符:[%c]", pos, ch_t);

				pos = ((ch_t - 48) * i) % u_len;
				ch_t = u_key[pos]; // 得到私密
				//LOGI("       密钥 位置:%d 字符:[%c]", pos, ch_t);

				ch_s = ch_e - ch_t; // 两个字符相减，得到明文
//				LOGI("       明文 [%d]  ", ch_s);
				source[i] = ch_s + 48;
			}
		}
		source[i] = '\0';
	}
	// 解码 end
//	LOGI("decoder[%s]", source);

	// 分离出频率和码 start
	i = 0;

	cmd_size = count_c(source, ch_c) - 1;

	if (cmd_size % 2 == 1) {
		isEven = 0;
		cmd_size++;
	}

	// LOGI("数组个数: %d ", cmd_size);
	int *cmd = (int*) calloc(cmd_size, sizeof(int)); // 自动初始化内存
	//int cmd[cmd_size] = {0};

	ch_find = strchr(source, ch_c);
	if (ch_find) {
//		LOGI("first pos: %d ", ch_find-source);
		ch_find++; // 略过第一个数字
		if (ch_find) {
			cf = atoi(ch_find);
			ch_find = strchr(ch_find, ch_c);
		}
//		LOGI("cf: %d ", cf);

		j = 0;
		while (ch_find) {
			ch_find++;
			if (ch_find) {
			//	cmd[j] = (1000000.000 / cf) * atoi(ch_find);
				//四舍五入，防止精度丢失
				cmd[j] = round((1000000.000 / cf) * atoi(ch_find));
//				LOGI(" pattern [%d]: %d ", j, cmd[j]);
				ch_find = strchr(ch_find, ch_c);
				j++;
			}
		}
	} else {
		LOGE("Error: data format");
		return -1;
	}
	// 分离出频率和码 end
	if (isEven == 0)
		cmd[cmd_size - 1] = cmd[cmd_size - 2]; //奇数，填充最后一个数据

	/*
	 * new Wave(19000, data, 44100, 8, 2, false, false, false, false);
	 (double freq, double[] data, int sampleFrequency,
	 int sampleSize, int channels, boolean bigEndian, boolean omitTail,
	 boolean square, boolean divide) {
	 */
	// 转换为 wave 数据 start , 存储于 buf
	jdouble freq = 19000;
	jint sampleFrequency = 44100;
//	jdouble freq = 9500;
//	jint sampleFrequency = 22050;
	int sampleSize = 8;
	int channels = 2;
	int bigEndian = 0, omitTail = 0, square = 0, divide = 0;

	jdouble sf = (jdouble) sampleFrequency / 1000000.0; // 频率
	int iDuration = omitTail > 0 ? cmd_size - 1 : cmd_size;
	int * durationsInSamplePeriods = (int*) calloc(iDuration, sizeof(int));

	int length = 0;
	int mod4 = 0;
//	LOGE(" iDuration: %d , %f " , iDuration, sf);
	for (i = 0; i < iDuration; i++) {
		if (cmd[i] < 0)
			cmd[i] = -cmd[i];
//		durationsInSamplePeriods[i] = (int) (sf * cmd[i]); // 没有四舍五入，直接舍去了
		//四舍五入，防止精度丢失
		durationsInSamplePeriods[i] = round( (sf * cmd[i]));

		//去掉补齐
		/* mod4 = durationsInSamplePeriods[i] % 4;
		if (mod4 == 0) {
		} else {
			if (durationsInSamplePeriods[i] > 15)
				durationsInSamplePeriods[i] -= mod4; // 大的数，向下取
			else
				durationsInSamplePeriods[i] += 4 - mod4; // 小的数据，向上取
		}*/

		length += durationsInSamplePeriods[i];
//		LOGE(" Test i:%d: %d  cmd:%d,  round:%d ", i , durationsInSamplePeriods[i], cmd[i], (int) round(sf * cmd[i]) );
	}

	jdouble c = ((jdouble) sampleFrequency) / ((jdouble) freq);
	jint buf_len = length * sampleSize / 8 * channels + 44;
	jbyte * buf = (jbyte*) calloc(buf_len, sizeof(jbyte));

	// 44 bytes header
	int header[] = { 82, 73, 70, 70, -118, 43, 0, 0, 87, 65, 86, 69, 102, 109,
			116, 32, 16, 0, 0, 0, 1, 0, 2, 0, 68, -84, 0, 0, -120, 88, 1, 0, 2,
			0, 8, 0, 100, 97, 116, 97, 102, 43, 0, 0 };
	for (i = 0; i < 44; i++) {
		buf[i] = header[i];
	}
	int filesize = buf_len - 8;
	buf[4] = (filesize >> 8 * (3 - 3) & 0xFF);
	buf[5] = (filesize >> 8 * (3 - 2) & 0xFF);
	buf[6] = (filesize >> 8 * (3 - 1) & 0xFF);
	buf[7] = (filesize >> 8 * (3 - 0) & 0xFF);

	int tempFile = buf_len - 8 - 36;
	buf[40] = (tempFile >> 8 * (3 - 3) & 0xFF);
	buf[41] = (tempFile >> 8 * (3 - 2) & 0xFF);
	buf[42] = (tempFile >> 8 * (3 - 1) & 0xFF);
	buf[43] = (tempFile >> 8 * (3 - 0) & 0xFF);

//    LOGE(" length: %d, buf_len:%d, filesize: %d, buf[4]: %d,buf[5]:%d " , length, buf_len, filesize, buf[4], buf[5]);

	int index = 44;
	for (i = 0; i < cmd_size - 1; i += 2) {
		// Handle pulse, even index

		int maxValue = 127;
		/*for (j = 0; j < durationsInSamplePeriods[i]; j++) {
			int mod = j%4 ;
			int val = (int) round(maxValue * sin(PI * mod / 2));
			buf[index++] = (jbyte)((jbyte) - val + 0x80);
			buf[index++] = (jbyte)((jbyte) val + 0x80);
		}
		int dploop = durationsInSamplePeriods[i] / 4;
		int mod = durationsInSamplePeriods[i] % 4;
		int jj = 0;
		for (j = 0; j < dploop; j++) {
			jj = 0;
			for (jj = 0; jj < 4; jj++) {
				int val = (int) round(maxValue * sin(PI * jj / 2));
				buf[index++] = (jbyte)((jbyte) - val + 0x80);
				buf[index++] = (jbyte)((jbyte) val + 0x80);
			}
		}
		if (mod > 1) { // 加半个周期
			jj = 0;
			for (jj = 0; jj < mod; jj++) {
				int val = (int) round(maxValue * sin(PI * jj / 2));
				buf[index++] = (jbyte)((jbyte) - val + 0x80);
				buf[index++] = (jbyte)((jbyte) val + 0x80);
			} //
		}*/

		for (j = 0; j < durationsInSamplePeriods[i]; j++) {

			jdouble t = ((jdouble) j) / (divide > 0 ? 2 * c : c);
			jdouble fraq = t - (int) t;
			jdouble s =square > 0 ?(fraq < 0.5 ? -1.0 : 1.0) : sin(2 * PI * (fraq));

			//    				if( i%2==0 && j%2==0 ) LOGE("jdouble i:%d, j:%d , t:%f, fraq:%f, s:%f, sin:%f", i, j, t, fraq, s, 2 * PI * fraq);
//			int maxValue = 127;
			if (sampleSize == 8) {
				int val = (int) round(maxValue * s);

				//最後一個變0
				if(j == durationsInSamplePeriods[i]-1){
					val = 0 ;
				}

				buf[index++] = (jbyte)((jbyte) val + 0x80);

				//    					if( i%2==0 && j%2==0 ) LOGE(" i:%d, j:%d , buf:%d", i, j, (jbyte) ((jbyte) val + 0x80));

				if (channels == 2)
					buf[index++] = (jbyte)((jbyte) - val + 0x80);
			} else {
				int val = (int) round(32767 * s);
				int low = (jbyte)((jbyte)(val & 0xFF) + 0x80);
				int high = (jbyte)((jbyte)(val >> 8) + 0x80);
				buf[index++] = bigEndian > 0 ? high : low;
				buf[index++] = bigEndian > 0 ? low : high;
				if (channels == 2) {
					val = -val;
					low = (jbyte)((jbyte)(val & 0xFF) + 0x80);
					high = (jbyte)((jbyte)(val >> 8) + 0x80);
					buf[index++] = bigEndian > 0 ? high : low;
					buf[index++] = bigEndian > 0 ? low : high;
				}
			}

		}

		// Gap, odd index
		if (omitTail == 0 || i < cmd_size - 2) {
			for (j = 0; j < durationsInSamplePeriods[i + 1]; j++) {
				//改为11kz发送
				int mod = j%4 ;
				int val = (int) round(maxValue * sin(PI * mod / 2));
				buf[index++] = (jbyte)((jbyte) - val + 0x80);
				buf[index++] = (jbyte)((jbyte) val + 0x80);
				/*int ch = 0;
				for (ch = 0; ch < channels; ch++) {
					buf[index++] = (jbyte)(0 + 0x80);
					if (sampleSize == 16)
						buf[index++] = (jbyte)(0 + 0x80);
				}*/
			}
		}
	}

	// 转换为 wave 数据 end

	//在Java中申请一块内存  以用来将C的数组传输给java程序
	jbyteArray jcmd = (*env)->NewByteArray(env, buf_len);
	(*env)->SetByteArrayRegion(env, jcmd, 0, buf_len, buf); // 存放码值

//	LOGE("Monitor: [ %d,  %d]",   buf[40], buf[41] );

//	for(i=0;i<buf_len;i=i+2){
//		LOGE("%d  [ %d,  %d]", i, buf[i], buf[i+1] );
//	}

//	LOGE("play start");
	jint channelConfig = 12; // AudioFormat.CHANNEL_OUT_STEREO
	jint audioFormat = 3; // pcm_8_bit: value-3
	jint streamType = 3; // AudioManager.STREAM_MUSIC
	jint mode = 0;

	//	AudioTrack at = new AudioTrack(AudioManager.STREAM_MUSIC,
	//					this._sampleRate, channelConfig, audioFormat, buf.length,
	//					AudioTrack.MODE_STATIC);
	//	at.write(buf, 0, buf.length);
	//	at.play();
	jclass mClass = (*env)->FindClass(env, "android/media/AudioTrack");
	//jclass mClass = (*env)->FindClass(env, "com/yaokan/devices/wavassit"); // android/media/AudioTrack
	if (mClass == NULL) {
		LOGI("can not find wavassist class");
		return -1;
	}
//	LOGI("Find wavassist class");

	jmethodID construct_id = (*env)->GetMethodID(env, mClass, "<init>",
			"(IIIIII)V");
	if (construct_id == NULL) {
		LOGI("can not get wavassist function");
		return -1;
	}
//	LOGI("Ok, get  wavassist function");

	// int streamType, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes, int mode)
	jobject audioTrack = (*env)->NewObject(env, mClass, construct_id,
			streamType, sampleFrequency, channelConfig, audioFormat, buf_len,
			mode);
	if (audioTrack == NULL) {
		LOGI("can not instance wavassist function");
		return -1;
	}
//	LOGI("OK, instance wavassist");

	jmethodID m_release = (*env)->GetMethodID(env, mClass, "release", "()V");
	if (m_release == NULL) {
		LOGI("can not get release function");
		return -1;
	}
//	LOGI("Ok, get   release function ----- 273");

	jmethodID m_write = (*env)->GetMethodID(env, mClass, "write", "([BII)I");
	if (m_write == NULL) {
		LOGI("can not instance m_write function");
		return -1;
	}
//	LOGI("OK, get  m_write");
	jint writelen = (*env)->CallIntMethod(env, audioTrack, m_write, jcmd,
			(jint) 0, buf_len);

//	LOGI("write len:%d s len:%d", writelen, buf_len);

//	jmethodID m_play = (*env)->GetMethodID(env, mClass, "play", "([B)V")
	jmethodID m_play = (*env)->GetMethodID(env, mClass, "play", "()V");
	if (m_play == NULL) {
		LOGI("can not get play function");
		return -1;
	}
//	LOGI("Ok, get  play function ----- 285");

	// invoke play
	(*env)->CallVoidMethod(env, audioTrack, m_play);

//	jint iState = 3; // 正在播放
//	jint iMaxLoop = 0;
//    while(iState==3){
//    	iMaxLoop++;
//    	iState = 1;
//    	LOGI(" state one:%d ", iState);
//
//    	iState = (*env)->CallIntMethod(env, audioTrack, m_state);
//    	LOGI(" state two:%d ", iState);
//    	if(iState == 1){
//    		LOGI("in 1 break ");
//    		break;
//    	}
//    	if( iMaxLoop>1000 ) {
//    		LOGI("in break ");
//    		break;
//    	}
//    	sleep(10);
//    }
	double lSleep = buf_len * 1000.0 * 1000.0 / sampleFrequency + 10; // us
	int iSleep = 6 * 10000;
	double hadSleep = 0;
//	LOGE("before sleep");
	while (hadSleep < lSleep) {
		usleep(iSleep);
		hadSleep += iSleep;
	}
//	LOGE("after sleep");
//	delay(123);
	// 每次最多sleep 10 ms
//	LOGI("sleep: %ld us", lSleep);

	(*env)->CallVoidMethod(env, audioTrack, m_release);

//	LOGE("play End release");

	// 释放内存
	(*env)->DeleteLocalRef(env, mClass);
//	(*env)->DeleteLocalRef(env, buf);
//	(*env)->DeleteLocalRef(env, m_play);
//	(*env)->DeleteLocalRef(env, m_write);
	(*env)->DeleteLocalRef(env, audioTrack);

//	(*env)->DeleteLocalRef(env, android_content_Context);

	free(source);
	free(cmd);
//	(*env)->ReleaseStringUTFChars(env, k, pub_key);
	(*env)->ReleaseStringUTFChars(env, e, encode);
//	LOGI("program end");
	return 1;
}

// 此方法，在System.loadLibrary()函数时，首先会去自动执行
jint JNI_OnLoad(JavaVM* vm, void* reserved) {
	jint result = -1;
	// 如果有需要，做一些初始化的工作

	result = JNI_VERSION_1_4;
	return result;
}

// 干挠用
/*jobject getInstance(JNIEnv *env, jclass obj_class) {
 jmethodID c_id = (*env)->GetMethodID(env, obj_class, "<init>", "()V");
 jobject obj = (*env)->NewObject(env, obj_class, c_id);
 return obj;
 }
 jobject getInstance_s(JNIEnv *env, jclass obj_class, jstring j_string) {
 jmethodID c_id = (*env)->GetMethodID(env, obj_class, "","(Ljava/lang/String;)V");
 jobject obj = (*env)->NewObject(env, obj_class, c_id, j_string);
 return obj;
 }
 void a_b_c() {
 int j = 16, i = 0;
 for (; i < 100; i++) {
 }
 j = (j * 100 + 123) / 12.9;
 }*/
